package com.jason.system.common.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.jason.system.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Date;

/**
 * @author jie
 * @version 1.0
 * success come from self-discipline
 * @date 2021/3/23 12:46
 * 描述: jwt工具类: 生成token签名, token校验
 */

@Component
@Slf4j
public class JwtUtil {

  /**
   * 过期时间：30min
   */
  private static final Long EXPIRE_TIME = 30*60*1000L;

  /**
   * /@value注解不能直接为静态变量赋值
   */
  @Value(value = "${myProperties.secret}")
  public void setSecret(String secret){
    SECRET = secret;
  }

  private static String SECRET;

  /**
   * 生成 token 时，指定 token 过期时间 EXPIRE_TIME 和签名密钥 SECRET，
   * 然后将 expireDate 和 username 写入 token 中，并使用带有密钥的 HS256 签名算法进行签名
   * @return String
   */
  public static String createToken(User user){
    String token = null;
    try{
      //签名时间
      Date issueDate = new Date(System.currentTimeMillis());
      //过期时间
      Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
      //加密算法
      Algorithm algorithm = Algorithm.HMAC256(SECRET);
      token = JWT.create()
              //jwt唯一id
              .withJWTId(user.getUId().toString())
              //签发者
              .withIssuer("jasonj.club")
              //面向用户
              .withAudience(user.getUsername())
              //签发时间
              .withIssuedAt(issueDate)
              //生效时间
              .withNotBefore(issueDate)
              .withClaim("username",user.getUsername())
              .withExpiresAt(expireDate)
              .sign(algorithm);
    }catch (UnsupportedEncodingException e){
      log.error("Fail to create token. {}",e.getMessage());
    }
    return token;
  }

  /**
   * 验证token，如果验证失败，便会抛出异常
   * @param token
   * @param username
   * @return true or false
   */
  public static void verify(String token,String username) throws Exception{
      Algorithm algorithm = Algorithm.HMAC256(SECRET);
      JWTVerifier verifier = JWT.require(algorithm)
              .withClaim("username",username)
              .build();
      //验证token
      verifier.verify(token);
  }

  /**
   * 在 createToken()方法里，有将 username 写入 token 中。现在可从 token 里获取 username
   * @param token
   * @return String
   */
  public static String getUsernameFromToken(String token){
    try {
      DecodedJWT decode = JWT.decode(token);
      String username = decode.getClaim("username").asString();
      return username;
    }catch (JWTDecodeException e){
      log.error("Failed to decode jwt. {}",e.getMessage());
      return null;
    }
  }
}
